package com.pucong.gitee.database.backup.utils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.pucong.gitee.database.backup.common.entity.sys.jwt.CheckResult;
import io.jsonwebtoken.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.security.SignatureException;
import java.util.Base64;
import java.util.Date;

/**
 * jwt工具类
 * @date 2020.08.21
 * @description
 *
 */
public class JwtUtils {

	/**
	 * @author ChenJunMa
	 * @date 2019年12月17日
	 * @description 签发JWT
	 * @param id
	 * @param subject   可以是JSON数据 尽可能少
	 * @param ttlMillis 有效期
	 * @return
	 */
	public static String createJWT(String id, String subject, long ttlMillis) {
		SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
		long nowMillis = System.currentTimeMillis();
		Date now = new Date(nowMillis);
		SecretKey secretKey = generalKey();
		JwtBuilder builder = Jwts.builder().setId(id).setSubject(subject) // 主题
				.setIssuer("zsFile") // 签发者
				.setIssuedAt(now) // 签发时间
				.signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙
		if (ttlMillis >= 0) {
			long expMillis = nowMillis + ttlMillis;
			Date expDate = new Date(expMillis);
			builder.setExpiration(expDate); // 过期时间
		}
		return builder.compact();
	}

	/**
	 * @author ChenJunMa
	 * @date 2019年12月17日
	 * @description 验证JWT
	 * @param jwtStr
	 * @return
	 */
	public static CheckResult validateJWT(String jwtStr) {
		CheckResult checkResult = new CheckResult();
		Claims claims = null;
		try {
			claims = parseJWT(jwtStr);
			checkResult.setSuccess(true);
			checkResult.setClaims(claims);
		} catch (ExpiredJwtException e) {
			checkResult.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE);
			checkResult.setSuccess(false);
		} catch (SignatureException e) {
			checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
			checkResult.setSuccess(false);
		} catch (Exception e) {
			checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
			checkResult.setSuccess(false);
		}
		return checkResult;
	}

	/**
	 * @author ChenJunMa
	 * @date 2019年12月17日
	 * @description 生成私钥
	 * @return
	 */
	private static SecretKey generalKey() {
		byte[] encodedKey = Base64.getDecoder().decode(SystemConstant.JWT_SECERT);
		SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
		return key;
	}

	/**
	 * @author ChenJunMa
	 * @date 2019年12月17日
	 * @description 解析JWT字符串
	 * @param jwt
	 * @return
	 * @throws Exception
	 */
	private static Claims parseJWT(String jwt) throws Exception {
		SecretKey secretKey = generalKey();
		return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
	}

	/**
	 * 获取请求中的token
	 * @return
	 */
	public static String getToken(){
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		//从cookie中获取token
		String lsso_token = null;
		Cookie[] cookieArr = request.getCookies();
		if (cookieArr != null && cookieArr.length > 0) {
			for (Cookie cookie : cookieArr) {
				if (SystemConstant.JWT_TOKEN.equals(cookie.getName())) {
					lsso_token = cookie.getValue();
				}
			}
		}
		// 没有则从header中拿token,方便swagger调试
		if(StringUtils.isBlank(lsso_token)){
			lsso_token = request.getHeader(SystemConstant.JWT_TOKEN);
		}
		return lsso_token;
	}

	public static String autoRefreshToken(CheckResult checkResult, String lsso_token) {
		String refreshToken = lsso_token;
		long expirationTime = checkResult.getClaims().getExpiration().getTime();
		long range = expirationTime - System.currentTimeMillis();
		if (range < SystemConstant.REFRESH_TIME) {
			refreshToken = refreshToken(lsso_token);
		}
		return refreshToken;
	}

	private static String refreshToken(String token) {
		CheckResult checkResult = JwtUtils.validateJWT(token);
		if (checkResult.isSuccess()) {
			Claims claims = checkResult.getClaims();
			String tokenId = claims.getId();
			String subject = claims.getSubject();
			String newToken = JwtUtils.createJWT(tokenId, subject, SystemConstant.TOKEN_EXPIRATION_TIME * 60 * 1000L);
			return newToken;
		} else {
			return checkResult.getErrCode();
		}
	}

	public static void main(String[] args) {
		//String createJWT = createJWT("192.168.200.150", "123321", 30 * 60 * 1000);
		CheckResult checkResult = validateJWT("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxIiwic3ViIjoie1wiaWRcIjpcIjFcIixcIm5hbWVcIjpcIui2hee6p-euoeeQhuWRmFwiLFwibG9naW5OYW1lXCI6XCJzdXBlcmFkbWluXCIsXCJlbWFpbFwiOlwiMTIzNDU2N1wiLFwib3JnQ29kZVwiOlwiMjAwMDAwXCIsXCJvcmdOYW1lXCI6bnVsbCxcInVuaXRDb2RlXCI6bnVsbCxcInVuaXROYW1lXCI6bnVsbCxcInRva2VuXCI6bnVsbCxcImlwXCI6XCIxMC4xLjEuMTJcIixcImFyZWFDb2RlXCI6bnVsbH0iLCJpc3MiOiJsc3NvIiwiaWF0IjoxNTk5ODA2MjQ3LCJleHAiOjE1OTk4MDYyNDd9.6VJi8rJ4ECIqbDhWK9HaRJWux3Jnm3iXTG3RDMXaijo");
		//System.out.println(createJWT);
		System.out.println(checkResult.toString());
	}
}
